extends Node

#记得！！！！！！！！/f运行函数得有一个参数，是做动画的那个Tween！！！！！！！！函数结尾得<参数名>.playback_speed=1恢复Tween的动画！！！！！！！！！！！！！！！

var sms=false#Tween
var function_list=[]#/f<数字>执行函数列表
var function_pause_list=[]#每句话/f的/前一个字符位置
var function_num_list=[]#每句话从前向后依次,每个/f执行的函数在列表中的位置
var wait_list=[]#每句话/w的/前一个字符位置
var wait_num_list=[]#每句话从前向后依次,每个/w等待的时间在等待时间列表中的位置
var wait_time_list=[0.1,0.2,0.5,1,2,4,5]#/w<数字>等待时间列表
var speak_fragments=[]
var wait=false#每句话后是否等待
var curent_char=0#当前显示字符
var character_time0=0#每个字符等待时间
var t6=0#richtext中当前[]导致需减去的字符数
var t7=0#\n导致需减去的字符数
var jumpable=false
var dlg_td0=Thread.new()#对话线程
var function_td0=Thread.new()#/f执行函数线程
var lock=Semaphore.new()#对话锁
var dlgbox=false#对话框
var dlghead=false#对话角色头像
var dlg_s=false#对话框是否在加载字符
var if_closeani=true#是否有关闭动画
enum ds {didnt_start=0,#当前状态
		force_stopping=1,
		openning_dialogue_box=2,
		dialoging=3,
		closing_dialogue_box=4}
var status=ds.didnt_start
var font=false#对话框字体
signal completed

#标签后不能跟数字。。。

func init():
	if(!sms):
		sms=Tween.new()
		add_child(sms)
		dlgbox=$"/root/Node2D/tdlg/dlg"
		dlghead=$"/root/Node2D/tdlg/spking"
		font=DynamicFont.new()
		font.font_data=load("res://data/fonts/VonwaonBitmap16px.ttf")
		dlgbox.add_font_override("normal_font",font)
		dlgbox.update()

func _ready():
	init()

func speak(SpeakFragments,functions,startani=true,closeani=true):#([[<头像>,[[<对话文字>，<字间隔时间>，<是否等待>],..]],...],[<函数0>,...])
	force_stop(false)
	status=ds.openning_dialogue_box
	init()#_ready初始化比别处调用慢[恼]
	dlgbox.bbcode_text=""
	lock.post()
	status=ds.force_stopping
	if(dlg_td0.is_active()):
		dlg_td0.wait_to_finish()
	status=ds.openning_dialogue_box
	if(function_td0.is_active()):
		function_td0.wait_to_finish()
	lock=Semaphore.new()
	dlg_td0=Thread.new()
	function_td0=Thread.new()
	function_list=functions
	speak_fragments=SpeakFragments
	dlgbox.bbcode_text=""#打开对话框
	dlgbox.visible_characters=0
	dlgbox.show()
	dlghead.texture=SpeakFragments[0][0]
	dlghead.show()
	if_closeani=closeani
	if(startani):
		sms.interpolate_property(dlgbox,"rect_size",Vector2(0,0),Vector2(940,240),1,Tween.TRANS_CUBIC,Tween.EASE_IN_OUT)
		sms.interpolate_property(dlgbox,"rect_position",Vector2(512,512),Vector2(78,264),1,Tween.TRANS_CUBIC,Tween.EASE_IN_OUT)
		sms.interpolate_property(dlghead,"position",Vector2(-32,296),Vector2(40,296),1,Tween.TRANS_CUBIC,Tween.EASE_IN_OUT)
		sms.start()
		yield(sms,"tween_all_completed")
	else:
		dlgbox.rect_size=Vector2(940,240)
		dlgbox.rect_position=Vector2(78,264)
		dlghead.position=Vector2(40,296)
	dlg_td0.start(self,"dialogue_starts_now",speak_fragments)

#	d.speak([
#		[chara["sys0"],[
#			["[shake rate=16 level=10][fade start=0 length=128]testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest_/w3text0/w0测试文本/w1零[/fade][/shake]",0.05,true],
#			["test/w3_text1//测试/f0文本一",0.05,true]
#		]]],
#		[funcref(self,"f0"),funcref(self,"f1")])

#t0当前对话列表	t1当前字符编号	t2/w或/f后数字后一字符编号	t6richtext[]标签导致减少字符数-1	t3数字指针	t4数字	t5数字位数*10
func dialogue_starts_now(spf):
	status=ds.dialoging
	dlg_s=true
	if(!sms.is_connected("tween_step",self,"dialogue_step")):
		sms.connect("tween_step",self,"dialogue_step")
	for t in spf:
		dlghead.texture=t[0]
		for t0 in t[1]:
			dlgbox.bbcode_text=t0[0]
			t6=t0[0].length()-dlgbox.text.length()
			t0[0]=dlgbox.text
			function_pause_list=[]
			wait_num_list=[]
			function_num_list=[]
			wait_list=[]
#					「屎山核心」
#初二留下的上古石山，因为不会正则表达式故手搓了一个字符串搜索&切除。
			var t1=0
			t6=0
			t7=0
			while(t1<t0[0].length()):#遍历对话字符串
				match(char(t0[0].ord_at(t1))):
					'\n':
						t7+=1
					'/':
						if(t1+3<=t0[0].length()):
							match(char(t0[0].ord_at(t1+1))):
								'/':
									t0[0]=t0[0].left(t1+1)+t0[0].right(t1+2)#剪掉/后面那个/
									t1-=1
								'f':
									function_pause_list.append(t1-1-t6-t7)
									var t2=t1+2
									while(t2<t0[0].length()):#48是0 57是9
										if((t0[0].ord_at(t2))>=48&&(t0[0].ord_at(t2)<=57)):
											t2+=1
										else:
											break
									var t4=0
									var t5=1
									for t3 in range(t2-1,t1+1,-1):
										t4+=(t0[0].ord_at(t3)-48)*t5
										t5*=10#获取/f后数字,存在t4
									function_num_list.append(t4)
									t0[0]=t0[0].left(t1)+t0[0].right(t2)#剪掉/f<数字>
									t1-=1
								'w':
									wait_list.append(t1-1-t6-t7)
									var t2=t1+2
									while(t2<t0[0].length()):#48是0 57是9
										if((t0[0].ord_at(t2))>=48&&(t0[0].ord_at(t2)<=57)):
											t2+=1
										else:
											break
									var t4=0
									var t5=1
									for t3 in range(t2-1,t1+1,-1):
										t4+=(t0[0].ord_at(t3)-48)*t5
										t5*=10
									wait_num_list.append(t4)
									t0[0]=t0[0].left(t1)+t0[0].right(t2)
									t1-=1
				t1+=1
			#print("txtl:",t0[0].length(),"\tt6:",t6,"\tt7:",t7,"\tfnl:",function_num_list,"\twnl:",wait_num_list,"\tfpl:",function_pause_list,"\twl:",wait_list,"\ntext:",t0[0],"\n\n")
			dlgbox.bbcode_text=t0[0]
			dlgbox.visible_characters=0
			character_time0=t0[1]
			if(t0.size()>=4):
				jumpable=t0[3]
			else:
				jumpable=true
			sms.interpolate_property(dlgbox,"visible_characters",0,dlgbox.bbcode_text.length()-t6-t7,(dlgbox.bbcode_text.length()-t6-t7)*character_time0,Tween.TRANS_LINEAR)
			if(t0[2]):#是否等待
				if(!sms.is_connected("tween_all_completed",self,"is_wait")):
					sms.connect("tween_all_completed",self,"is_wait")
			else:
				if(!sms.is_connected("tween_all_completed",self,"no_wait")):
					sms.connect("tween_all_completed",self,"no_wait")
			sms.start()
			lock.wait()
			if(status==ds.force_stopping):
				break
		if(status==ds.force_stopping):
			break
	if(status!=ds.force_stopping):
		if(if_closeani):
			status=ds.closing_dialogue_box
			dlg_s=false
			dlgbox.bbcode_text=""#关闭对话框
			sms.interpolate_property(dlgbox,"rect_size",Vector2(940,240),Vector2(0,0),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
			sms.interpolate_property(dlgbox,"rect_position",Vector2(78,264),Vector2(512,512),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
			sms.interpolate_property(dlghead,"position",Vector2(40,296),Vector2(-32,296),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
			sms.start()
			yield(sms,"tween_all_completed")
		else:
			dlgbox.rect_size=Vector2(0,0)
			dlgbox.rect_position=Vector2(512,512)
			dlghead.position=Vector2(-32,296)
		status=ds.didnt_start
		emit_signal("completed")

func force_stop(ani=true):#是否有关对话框动画
	init()
	lock.post()
	status=ds.force_stopping
	if sms.is_active():
		sms.remove_all()
	if(sms.is_connected("tween_all_completed",self,"no_wait")):
		sms.disconnect("tween_all_completed",self,"no_wait")
	if(sms.is_connected("tween_all_completed",self,"is_wait")):
		sms.disconnect("tween_all_completed",self,"is_wait")
	#call_deferred("reset_ui_state",ani)
	if(ani):
		yield(reset_ui_state(ani),"completed")
	else:
		reset_ui_state(ani)
	var cleanup_data={
		"function_pause_list":[],
		"wait_list":[],
		"function_num_list":[],
		"wait_num_list":[],
		"speak_fragments":[]
	}
	function_pause_list=cleanup_data.function_pause_list
	wait_list=cleanup_data.wait_list
	function_num_list=cleanup_data.function_num_list
	wait_num_list=cleanup_data.wait_num_list
	speak_fragments=cleanup_data.speak_fragments
#	if dlg_td0:
#		dlg_td0.call_deferred("free")
#	if function_td0:
#		function_td0.call_deferred("free")
#	dlg_td0=Thread.new()
#	function_td0=Thread.new()
	status=ds.didnt_start

func reset_ui_state(ani):
	dlgbox.bbcode_text=""
	if(ani):
		sms.interpolate_property(dlgbox,"rect_size",dlgbox.rect_size,Vector2(0,0),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
		sms.interpolate_property(dlgbox,"rect_position",dlgbox.rect_position,Vector2(512,512),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
		sms.interpolate_property(dlghead,"position",dlghead.position,Vector2(-32,296),1,Tween.TRANS_CUBIC,Tween.EASE_OUT)
		sms.start()
		yield(sms,"tween_all_completed")
	else:
		dlgbox.rect_size=Vector2(0,0)
		dlgbox.rect_position=Vector2(512,512)
		dlghead.position=Vector2(-32,296)
	dlgbox.bbcode_text=""
	dlgbox.visible_characters=-1

func dialogue_step(_e0,_e1,_e2,_e3):#tween_step信号链接的函数自带4个参数必填
	curent_char=dlgbox.visible_characters-1
	while(wait_list.size()>0):
		if(wait_list[0]==curent_char):
			sms.playback_speed=0
			yield(get_tree().create_timer(wait_time_list[wait_num_list[0]]),"timeout")
			sms.playback_speed=1
			wait_list.pop_front()
			wait_num_list.pop_front()
		else:
			break
	while(function_pause_list.size()>0):#无元素数组不可访问[0]
		if(function_pause_list[0]==curent_char):#这里的if-elif-else逻辑要写完美好像只能用goto
			sms.playback_speed=0
			function_td0.start(self,"run_function",[function_list[function_num_list[0]],sms])#thread.start只能传一个参数[恼]
			function_td0.wait_to_finish()#这里不等的话下一次运行这次的还没跑完
			function_num_list.pop_front()
			function_pause_list.pop_front()
		else:
			break

func run_function(r):
	r[0].call_func(r[1])

func no_wait():
	lock.post()

func is_wait():
	wait=true

func _exit_tree():
	lock.post()

func resize_font(size,path="res://data/fonts/凤凰点阵体16px.ttf"):
	init()
	font.font_data=load(path)
	font.size=size
	dlgbox.add_font_override("normal_font",font)
	dlgbox.update()

func _process(_delta):
	if(dlg_s):
		if(i.keys.accept)&&(dlgbox.visible_characters<dlgbox.bbcode_text.length()&&jumpable):#跳过对话
			if(function_pause_list.size()>0):
				sms.remove(dlgbox,"visible_characters")
				dlgbox.visible_characters=function_pause_list[0]
				curent_char=function_pause_list[0]
				sms.interpolate_property(dlgbox,"visible_characters",function_pause_list[0],dlgbox.bbcode_text.length()-t6-t7,(dlgbox.bbcode_text.length()-function_pause_list[0]-t6-t7)*character_time0,Tween.TRANS_LINEAR)
				sms.playback_speed=0
				sms.start()
				function_td0.start(self,"run_function",[function_list[function_num_list[0]],sms])
				function_td0.wait_to_finish()
				function_num_list.pop_front()
				function_pause_list.pop_front()
			else:
				dlgbox.visible_characters=dlgbox.bbcode_text.length()
				sms.remove(dlgbox,"visible_characters")
	if(wait&&i.keys.accept):
		wait=false
		lock.post()
